#pragma once


#include <memory>
#include "Containers/Containers.h"
#include "Reflection/FunctionID.h"

#include "ScriptRuntime/ByteCode/ByteCodeInstruction.h"
#include "ScriptRuntime/ScriptAccessLevel.h"

#include "ByteCodeFile.h"

#include "ScriptRuntime/ByteCode/ByteCodeSectionTypes.h"

class CByteCodeFile;

class CByteCodeReader
{
public:

    CByteCodeReader(std::shared_ptr<CByteCodeFile> InByteCodeFile, TOptional<uint32_t> InOffset = TOptional<uint32_t>());

    CByteCodeReader& operator >> (EByteCodeInstructions& Instruction);

    CByteCodeReader& operator >> (EByteCodeSectionType& SectionType);

    CByteCodeReader& operator >> (STypeID& Value);

    CByteCodeReader& operator >> (TVector<uint32_t>& Value);    

    CByteCodeReader& operator >> (SFunctionID& Value);

    CByteCodeReader& operator >> (TVector<SFunctionID>& Value);

    CByteCodeReader& operator >> (bool & Value);

    CByteCodeReader& operator >> (char32_t& Value);

    CByteCodeReader& operator >> (uint8_t& Value);

    CByteCodeReader& operator >> (uint16_t& Value);

    CByteCodeReader& operator >> (uint32_t& Value);

    CByteCodeReader& operator >> (uint64_t& Value);

    CByteCodeReader& operator >> (int8_t& Value);

    CByteCodeReader& operator >> (int16_t& Value);

    CByteCodeReader& operator >> (int32_t& Value);

    CByteCodeReader& operator >> (int64_t& Value);

    CByteCodeReader& operator >> (float& Value);

    CByteCodeReader& operator >> (double& Value);

    CByteCodeReader& operator >> (CString& Value);

    CByteCodeReader& operator >> (CConstantValue& Value);

    CByteCodeReader& operator >> (CByteCodeFile::SBreakpointInfo& BreakpointInfo);

    CByteCodeReader& operator >> (TVector<int64_t>& Value);

    CByteCodeReader& operator >> (TVector<CString>& Value);

    CByteCodeReader& operator >> (CByteCodeFile::STypeInfo& TypeInfo);
    
    CByteCodeReader& operator >> (TVector<CByteCodeFile::STypeInfo>& TypeInfos);

    CByteCodeReader& operator >> (CByteCodeFile::SVariableInfo& VariableInfo);

    CByteCodeReader& operator >> (EScriptAccessLevel& AccessLevel);

    CByteCodeReader& operator >> (CByteCodeFile::SMemberDecorator& Decorator);

    CByteCodeReader& operator >> (CByteCodeFile::SClassInfo& ClassInfo);

    CByteCodeReader& operator >> (CByteCodeFile::SGeneralizedClasseInfo& ClassInfo);

    CByteCodeReader& operator >> (CByteCodeFile::SFunctionType& FunctionType);

    CByteCodeReader& operator >> (CByteCodeFile::SFieldInfo& FieldInfo);

    CByteCodeReader& operator >> (CByteCodeFile::SFunctionInfo& FunctionInfo);

    CByteCodeReader& operator >> (CByteCodeFile::SFunctionCallInfo& FunctionCallInfo);


    //get current offset
    uint32_t GetOffset() const;

    //set current offset
    void SetOffset(uint32_t InOffset);

    //get byte code file
    std::shared_ptr<CByteCodeFile> GetByteCodeFile() const;
protected:
    std::shared_ptr<CByteCodeFile> ByteCodeFile;
    uint32_t Offset = 0;

    TVector<CString> StringTable; 

    TVector<CByteCodeFile::SSourceCodeFile> SourceCodeFileTable;
    
    void Begin();
public:
    
    SDecoratedType ParseTypeInfo(const CByteCodeFile::STypeInfo & InInfo);


    bool Finished();

    CByteCodeFile::SSourceCodeFile& GetSourceFile(uint32_t Index);

    uint32_t GetSourceFileCount();
};
